module ArithmeticLogicunit(

	input	[4:0]	i_ALU_alcode,
	input	[31:0]	i_ALU_operand1,
	input	[31:0]	i_ALU_operand2,
	input	[15:0]	i_ALU_imm,
	
	output	[31:0]	o_ALU_result,
	output			o_ALU_overflow

);
	
	wire	[4:0]	alcode = i_ALU_alcode;
	
	wire	[31:0]	op1 = i_ALU_operand1;
	wire	[31:0]	op2 = i_ALU_operand2;
	wire	[31:0]	imm = i_ALU_imm;
	wire signed	[31:0]	sop0 = i_ALU_operand1;
	wire signed	[31:0]	sop1 = i_ALU_operand2;
	wire signed [31:0]	simm = i_ALU_imm;
	
	wire	[32:0]	add = op1 + op2;
	wire	[32:0]	sub = op1 - op2;
	wire	[32:0]	addi= op1 + imm;
	
	wire	[32:0]	ADD 	= (alcode==5'd1 ) ? add 				: 32'd0;
	wire	[32:0]	ADDI	= (alcode==5'd2 ) ? addi 				: 32'd0;
	wire	[32:0]	ADDU 	= (alcode==5'd3 ) ? {1'b0, add[31:0]}	: 32'd0;
	wire	[32:0]	ADDIU	= (alcode==5'd4 ) ? {1'b0, addi[31:0]}	: 32'd0;
	wire	[32:0]	SUB 	= (alcode==5'd23) ? sub					: 32'd0;
	wire	[32:0]	SUBU 	= (alcode==5'd24) ? {1'b0, sub[31:0]}	: 32'd0;
	
	wire ov_add = (i_alu_opcode == 6'd1 ) ? (add[32]  ^ add[31]  ^ op1[31] ^ op2[31]) : 1'b0;
	wire ov_addi= (i_alu_opcode == 6'd2 ) ? (addi[32] ^ addi[31] ^ op1[31] ^ imm[31]) : 1'b0;
	wire ov_sub = (i_alu_opcode == 6'd23) ? (sub[32]  ^ sub[31]  ^ op1[31] ^ op2[31]) : 1'b0;
	assign	o_ALU_overflow = ov_add | ov_addi | ov_sub;
	
	wire	[31:0]	SLT	  = (alcode==5'd5) ? {31'd0, sop0 < sop1}	:32'd0;
	wire	[31:0]	SLTI  = (alcode==5'd6) ? {31'd0, sop0 < simm}	:32'd0;
	wire	[31:0]	SLIU  = (alcode==5'd7) ? {31'd0, op0 < op1}		:32'd0;
	wire	[31:0]	SLTIU = (alcode==5'd8) ? {31'd0, op0 < imm}		:32'd0;
	
	wire	[31:0]	AND	= (alcode==5'd9 ) ? op1 & op2 			: 32'd0;
	wire	[31:0]	ANDI= (alcode==5'd10) ? op1 & imm 			: 32'd0;
	wire	[31:0]	OR	= (alcode==5'd11) ? op1 | op2 			: 32'd0;
	wire	[31:0]	ORI	= (alcode==5'd11) ? op1 | imm 			: 32'd0;
	wire	[31:0]	XOR	= (alcode==5'd13) ? op1 ^ op2 			: 32'd0;
	wire	[31:0]	XORI= (alcode==5'd14) ? op1 ^ imm 			: 32'd0;
	wire	[31:0]	NOR	= (alcode==5'd15) ? ~(op1 | op2) 		: 32'd0;
	wire	[31:0]	LUI	= (alcode==5'd16) ? {imm[15], 16'd0} 	: 32'd0;

	wire	[31:0]	SLL	= (alcode==5'd17)? op2 << imm[10:6] 	: 32'd0;
	wire	[31:0]	SLLV= (alcode==5'd18)? op2 << op1[4:0]		: 32'd0;
	wire	[31:0]	SRA	= (alcode==5'd19)? sop2 >>> simm[10:6]	: 32'd0;
	wire	[31:0]	SRAV= (alcode==5'd20)? sop2 >>> sop1[4:0] 	: 32'd0;
	wire	[31:0]	SRL	= (alcode==5'd21)? op2 >> imm[10:6]		: 32'd0;
	wire	[31:0]	SRLV= (alcode==5'd22)? op2 >> op1[4:0]		: 32'd0;

	wire	[31:0]	CLO = (alcode==5'd25)? 32'd0 : 32'd0;
	wire	[31:0]	CLZ = (alcode==5'd25)? 32'd0 : 32'd0;

	assign	o_ALU_result = 	ADD[31:0]	|ADDI[31:0]	|ADDU[31:0]	|ADDIU[31:0]|SUB[31:0]	|SUBU[31:0]	|
							SLT  	|SLTI  	|SLTU  	|SLTIU	|
							AND  	|ANDI  	|OR  	|ORI	|XOR  	|XORI  	|NOR  	|LUI	|
							SLL  	|SLLV  	|SRA  	|SRAV	|SRL  	|SRLV	|
							CLO  	|CLZ;

endmodule